﻿using System;
using BeefyEventAggregator;
using MATtutsLab.Entities;
using MATtutsLab.MVP.Events;
using MATtutsLab.MVP.Presenters;
using MATtutsLab.MVP.Views;
using MATtutsLab.Repositories;
using NUnit.Framework;
using Rhino.Mocks;

namespace MATtutsLab.Specs
{
    public abstract class AddEditZombieMoviePresenterSpecsContext
    {
        protected IAddEditZombieMovieView View;
        protected AddEditZombieMoviePresenter Presenter;
        protected IMovieRepository Repository;
        protected IEventPublisher EventPublisher;

        [TestFixtureSetUp]
        protected virtual void Context()
        {
            View = MockRepository.GenerateMock<IAddEditZombieMovieView>();
            Repository = MockRepository.GenerateMock<IMovieRepository>();
            EventPublisher = MockRepository.GenerateMock<IEventPublisher>();

            Presenter = new AddEditZombieMoviePresenter(View, Repository, EventPublisher);
        }
    }

    /// <summary>
    /// Adding a new Zombie Movie
    /// </summary>
    [TestFixture]
    public class When_initializing_View_with_a_new_movie : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();
        }

        [Test]
        public void Should_disable_ability_to_save()
        {
            View.AssertWasCalled(view => view.DisableSave());
        }

        [Test]
        public void Should_set_view_title_to_Add_Movie()
        {
            View.AssertWasCalled(view => view.SetTitleToAddMovie());
        }
    }

    /// <summary>
    /// Editing a Zombie Movie
    /// </summary>
    [TestFixture]
    public class When_initializing_View_with_an_existing_movie_AND_movie_is_not_null : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            var movieToEdit = new Movie();

            Presenter.InitializeView(movieToEdit);
        }

        [Test]
        public void Should_set_form_values_from_existing_movie()
        {
            View.AssertWasCalled(view => view.LoadFormValuesFromExistingMovie(null), options => options.IgnoreArguments());
        }

        [Test]
        public void Should_set_view_title_to_Edit_Movie()
        {
            View.AssertWasCalled(view => view.SetTitleToEditMovie());
        }
    }

    /// <summary>
    /// Editing a Zombie Movie
    /// </summary>
    [TestFixture]
    public class When_initializing_View_with_an_existing_movie_AND_movie_IS_null : AddEditZombieMoviePresenterSpecsContext
    {
        [Test]
        [ExpectedException(typeof(NullReferenceException))]
        public void Should_throw_null_reference_exception()
        {
            Presenter.InitializeView(null);
        }
    }

    [TestFixture]
    public class When_form_is_not_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.TitleEntered("");
            Presenter.ShortDescriptionEntered("");
            Presenter.LongDescriptionEntered("");
            Presenter.ImageUrlEntered("");
        }

        [Test]
        public void Should_disable_ability_to_save()
        {
            View.AssertWasCalled(view => view.DisableSave());
        }
    }

    [TestFixture]
    public class When_form_IS_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.TitleEntered("title");
            Presenter.ShortDescriptionEntered("short description");
            Presenter.LongDescriptionEntered("long description");
            Presenter.ImageUrlEntered("myUrl");
        }

        [Test]
        public void Should_enable_ability_to_save()
        {
            View.AssertWasCalled(view => view.EnableSave());
        }
    }

    [TestFixture]
    public class When_title_IS_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.TitleEntered("title");
        }

        [Test]
        public void Should_hide_TitleIsInvalidMessage()
        {
            View.AssertWasCalled(view => view.HideTitleIsInvalidMessage());
        }
    }

    [TestFixture]
    public class When_title_is_NOT_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.TitleEntered("");
        }

        [Test]
        public void Should_show_TitleIsInvalidMessage()
        {
            View.AssertWasCalled(view => view.ShowTitleIsInvalidMessage());
        }
    }

    [TestFixture]
    public class When_shortDescription_IS_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.ShortDescriptionEntered("my short description");
        }

        [Test]
        public void Should_hide_ShortDescriptionIsInvalidMessage()
        {
            View.AssertWasCalled(view => view.HideShortDescriptionIsInvalidMessage());
        }
    }

    [TestFixture]
    public class When_shortDescription_is_NOT_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.ShortDescriptionEntered("");
        }

        [Test]
        public void Should_show_ShortDescriptionIsInvalidMessage()
        {
            View.AssertWasCalled(view => view.ShowShortDescriptionIsInvalidMessage());
        }
    }

    [TestFixture]
    public class When_longDescription_IS_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.LongDescriptionEntered("my long description");
        }

        [Test]
        public void Should_hide_LongDescriptionIsInvalidMessage()
        {
            View.AssertWasCalled(view => view.HideLongDescriptionIsInvalidMessage());
        }
    }

    [TestFixture]
    public class When_longDescription_is_NOT_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.LongDescriptionEntered("");
        }

        [Test]
        public void Should_show_LongDescriptionIsInvalidMessage()
        {
            View.AssertWasCalled(view => view.ShowLongDescriptionIsInvalidMessage());
        }
    }

    [TestFixture]
    public class When_Image_url_IS_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.ImageUrlEntered("myUrl");
        }

        [Test]
        public void Should_show_ImageUrlIsInValidMessage()
        {
            View.AssertWasCalled(view => view.HideImageUrlIsInvalidMessage());
        }
    }

    [TestFixture]
    public class When_Image_url_IS_NOT_valid : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();

            Presenter.ImageUrlEntered("");
        }

        [Test]
        public void Should_hide_ImageUrlIsInValidMessage()
        {
            View.AssertWasCalled(view => view.ShowImageUrlIsInvalidMessage());
        }
    }

    [TestFixture]
    public class When_saving_movie : AddEditZombieMoviePresenterSpecsContext
    {
        protected override void Context()
        {
            base.Context();

            Presenter.InitializeView();
            Presenter.SaveRequested();
        }

        [Test]
        public void Should_make_call_to_movie_repository_save_method()
        {
            Repository.AssertWasCalled(repo => repo.Save(null), option => option.IgnoreArguments());
        }

        [Test]
        public void Should_close_the_form_after_saving()
        {
            View.AssertWasCalled(view => view.CloseRequested());
        }

        [Test]
        public void Should_publish_updated_movie_event()
        {
            EventPublisher.AssertWasCalled(eventPublisher => eventPublisher.Publish(new MovieUpdatedEvent(null)), options => options.IgnoreArguments());
        }
    }
}
